#include "common_def.h"
#include "soc_osal.h"
#include "app_init.h"
#include "securec.h"
#include "cJSON.h"

#include <los_sem.h>

#include "sle_low_latency.h"
#include "sle_server.h"
#include "sle_server_adv.h"
#include "sle_device_discovery.h"
#include "sle_errcode.h"

#include "bsp_led.h"
#include "bsp_dht11.h"
#include "bsp_ldr.h"
#include "bsp_oled.h"
#include "bsp_uart.h"
#include <math.h>   // 数学函数库，提供sinf、sqrtf、roundf等数学运算
#include <unistd.h> // Unix标准库，提供usleep函数（用于Linux/Unix环境）
#include "ds18b20.h"
#define CODE_LOG "[ShipSystem CollectionNode]"

// #define SLE_SERVER_MSG_QUEUE_LEN 5
// #define SLE_SERVER_MSG_QUEUE_MAX_SIZE 32
// #define SLE_SERVER_QUEUE_DELAY 0xFFFFFFFF
// #define SLE_SERVER_BUFF_MAX_SIZE 800

// 通信串口配置参数
static uint8_t g_uart_gui_rx_buff[512] = {0};
static uart_buffer_config_t g_uart_gui_buffer_config = {
    .rx_buffer = g_uart_gui_rx_buff,
    .rx_buffer_size = 512,
};
Attitude ship_attitude = {0};
// 任务句柄
osal_task *g_TaskHandle_LedBlinky = NULL; // LED闪烁任务

// 定义SLE设备地址 FF + "ship" + Node_ID（0x02）
uint8_t g_sle_device_addr[SLE_ADDR_LEN] = {0xFF, 0x73, 0x68, 0x69, 0x70, 0x02};
static uint8_t g_sle_status = 0; // SLE状态 0：未连接 1：连接成功

static void ssaps_server_read_request_cbk(uint8_t server_id, uint16_t conn_id, ssaps_req_read_cb_t *read_cb_para, errcode_t status)
{
    osal_printk("%s ssaps read request cbk callback server_id:%x, conn_id:%x, handle:%x, status:%x\r\n",
                CODE_LOG, server_id, conn_id, read_cb_para->handle, status);
}
static void ssaps_server_write_request_cbk(uint8_t server_id, uint16_t conn_id, ssaps_req_write_cb_t *write_cb_para, errcode_t status)
{
    osal_printk("%s ssaps write request callback cbk server_id:%x, conn_id:%x, handle:%x, status:%x\r\n",
                CODE_LOG, server_id, conn_id, write_cb_para->handle, status);
    if ((write_cb_para->length > 0) && write_cb_para->value)
    {
        osal_printk("\n sle uart recived data : %s\r\n", write_cb_para->value);
    }
}

static void sle_server_write_msgqueue(uint8_t *buffer_addr, uint16_t buffer_size)
{
    // osal_printk("%s sle_server_write_msgqueue. buffer_size:%d, buffer:%s\n", CODE_LOG, buffer_size, buffer_addr);

    if (memcmp(buffer_addr, "sle_connect", buffer_size) == 0)
    {
        osal_printk("%s sle_connect\r\n", CODE_LOG);

        // 设置SLE连接状态为 已连接
        g_sle_status = 1;

        // 关闭LED闪烁
        osal_kthread_suspend(g_TaskHandle_LedBlinky);
        bsp_led_set_state(LED1, LED_ON);
    }
    else if (memcmp(buffer_addr, "sle_disconnect", buffer_size) == 0)
    {
        osal_printk("%s sle_disconnect\r\n", CODE_LOG);

        // 设置SLE连接状态为 断开连接
        g_sle_status = 0;

        // 开启LED闪烁
        osal_kthread_resume(g_TaskHandle_LedBlinky);

        // 客户端断开连接，重新开启设备公开
        errcode_t ret = sle_start_announce(1);
        if (ret != ERRCODE_SLE_SUCCESS)
        {
            osal_printk("%s sle_connect_state_changed_cbk, sle_start_announce fail :%02x\r\n", CODE_LOG, ret);
        }
    }
}

/**
 * @brief  初始化uuid server。
 * @retval ERRCODE_SUCC 成功。
 * @retval Other        失败，参考 @ref errcode_t 。
 */
errcode_t sle_server_init(void)
{
    errcode_t ret;

    // 注册SLE控制消息回调函数
    sle_server_register_msg(sle_server_write_msgqueue);

    // 使能SLE
    ret = enable_sle();
    if (ret != ERRCODE_SUCC)
    {
        osal_printk("%s sle enbale fail!\n", CODE_LOG);

        return ret;
    }

    // 注册SLE设备发现回调函数
    ret = sle_announce_register_cbks();
    if (ret != ERRCODE_SLE_SUCCESS)
    {
        osal_printk("%s sle_server_init,sle_announce_register_cbks fail: %x\n", CODE_LOG, ret);

        return ret;
    }

    // 注册SLE连接管理回调函数
    ret = sle_conn_register_cbks();
    if (ret != ERRCODE_SLE_SUCCESS)
    {
        osal_printk("%s sle_server_init, sle_conn_register_cbks fail: %x\n", CODE_LOG, ret);

        return ret;
    }

    // 注册SLE SSAPS回调函数
    ret = sle_ssaps_register_cbks(ssaps_server_read_request_cbk, ssaps_server_write_request_cbk);
    if (ret != ERRCODE_SLE_SUCCESS)
    {
        osal_printk("%s sle_server_init, sle_ssaps_register_cbks fail :%x\r\n", CODE_LOG, ret);
        return ret;
    }

    // 初始化SLE服务端
    ret = sle_server_add();
    if (ret != ERRCODE_SLE_SUCCESS)
    {
        osal_printk("%s sle_server_init, sle_server_add fail :%x\r\n", CODE_LOG, ret);
        return ret;
    }

    // 初始化SLE服务端设备公开功能
    ret = sle_server_adv_init(CONFIG_SLE_SERVER_NAME, "CollectionNode", g_sle_device_addr, SLE_ADDR_LEN);
    if (ret != ERRCODE_SLE_SUCCESS)
    {
        osal_printk("%s sle_server_init, sle_server_adv_init fail :%x\r\n", CODE_LOG, ret);
        return ret;
    }

    osal_printk("%s sle init ok\r\n", CODE_LOG);

    return ERRCODE_SLE_SUCCESS;
}

/**
 * @brief  创建Json消息数据。
 * @param  [in] msg_data_type 消息数据类型。
 * @param  [in] msg_data_unit 消息数据单位。
 * @param  [in] msg_data_value 消息数据值。
 * @retval 成功， 返回Json消息数据字符串。该字符串使用完成需要使用 free() 释放内存。
 * @retval 失败， 返回 NULL。
 */
char *cJSON_MessageCreat(char *msg_data_type, char *msg_data_unit, uint16_t msg_data_value)
{
    // 创建JSON对象
    cJSON *root = cJSON_CreateObject();
    if (root == NULL)
    {
        osal_printk("%s cJSON_CreateObject fail\r\n", CODE_LOG);

        return NULL;
    }

    // 添加type字段
    if (cJSON_AddStringToObject(root, "type", msg_data_type) == NULL)
    {
        osal_printk("%s cJSON_AddStringToObject type fail\r\n", CODE_LOG);

        cJSON_Delete(root);
        return NULL;
    }

    // 添加value字段
    if (cJSON_AddNumberToObject(root, "value", msg_data_value) == NULL)
    {
        osal_printk("%s cJSON_AddNumberToObject value fail\r\n", CODE_LOG);

        cJSON_Delete(root);
        return NULL;
    }

    // 添加unit字段
    if (cJSON_AddStringToObject(root, "unit", msg_data_unit) == NULL)
    {
        osal_printk("%s cJSON_AddStringToObject unit fail\r\n", CODE_LOG);

        cJSON_Delete(root);
        return NULL;
    }

    // 将JSON对象转换为字符串
    char *json_string = cJSON_Print(root);
    osal_printk(json_string);
    // 释放JSON对象，并返回字符串
    cJSON_Delete(root);
    return json_string;
}
char *JSON_data_combination(char data[][15], uint8_t len)
{
    cJSON *root = cJSON_CreateObject();
    if (root == NULL)
    {
        osal_printk("%s cJSON_CreateObject fail\r\n", CODE_LOG);

        return NULL;
    }
    cJSON_AddStringToObject(root, "equipment", "collect");
    cJSON_AddStringToObject(root, "temperature", data[0]);
    cJSON_AddStringToObject(root, "hum", data[1]);
    cJSON_AddStringToObject(root, "illuminance", data[2]);
    cJSON_AddStringToObject(root, "water_temp", data[3]);
    cJSON_AddStringToObject(root, "PH", data[4]);
    cJSON_AddStringToObject(root, "solubility", data[5]);
    cJSON_AddStringToObject(root, "turbidity", data[6]);
    cJSON_AddStringToObject(root, "longitude", data[7]);
    cJSON_AddStringToObject(root, "latitude", data[8]);

    char *string = cJSON_Print(root);
    cJSON_Delete(root);
    return string;
}

static void *ShipSystem_LedBlinky_task(const char *arg)
{
    unused(arg);

    bsp_led_init(LED1, CONFIG_LED1_PIN);
    bsp_led_init(LED2, CONFIG_LED2_PIN);

    bsp_led_set_state(LED2, LED_ON);

    while (1)
    {
        bsp_led_toggle(LED1);
        osal_msleep(500);
    }

    return NULL;
}
double coordinate[2];
void GPS_uart_rx_callback(const void *buffer, uint16_t length, bool error)
{
    const char *string = buffer;
    int16_t temp = 0;
    double temp1 = 0;

    char *temp2 = strstr(string, "$GNGLL,");
    if (temp2 != NULL)
    {
        temp2 += 7;
        // 北纬
        temp1 = strtod(temp2, NULL);
        temp = (int16_t)(temp1 / 100);
        temp1 -= (temp * 100);
        coordinate[0] = temp + (temp1 / 60.0);
        // 东经
        temp1 = strtod(temp2 + 13, NULL);
        temp = (int16_t)(temp1 / 100);
        temp1 -= (temp * 100);
        coordinate[1] = temp + (temp1 / 60.0);
    }
}

double PH, solubility, turbidity, ldr_value, water_temp;
DHT11_Data_TypeDef DHT11_Data;
static void *ShipSystem_CollectionNode_task(const char *arg)
{
    unused(arg);

    // 开启LED闪烁任务
    osal_kthread_lock();
    g_TaskHandle_LedBlinky = osal_kthread_create((osal_kthread_handler)ShipSystem_LedBlinky_task, 0, "ShipSystem_LedBlinky_Task", 0x200);
    if (g_TaskHandle_LedBlinky != NULL)
    {
        osal_kthread_set_priority(g_TaskHandle_LedBlinky, 32);
    }
    osal_kthread_unlock();

    // 初始化SLE服务
    sle_server_init();

    // 初始化DHT11设备
    bsp_dht11_init(CONFIG_DHT11_PIN);

    // 初始化光敏电阻设备
    bsp_ldr_init(CONFIG_LDR_ADC_CHANNEL);
    bsp_ldr_init(ADC_CHANNEL_2);
    bsp_ldr_init(ADC_CHANNEL_3);
    bsp_ldr_init(ADC_CHANNEL_4);
    // 初始化OLED显示
    bsp_oled_Init(CONFIG_OLED_I2C_BUS);

    DS18B20_Init();

    // bsp_oled_DrawString(0, 20, "T:    H:   ", Font_7x10, White);
    // bsp_oled_DrawString(0, 40, "L:    ", Font_7x10, White);
    // bsp_oled_UpdateScreen();

    bsp_uart_init(UART_BUS_2, 115200, &g_uart_gui_buffer_config);
    bsp_uart_register_rx(UART_BUS_2, GPS_uart_rx_callback);

    while (1)
    {

        // DHT11数据采集

        char oled_data[8] = {0};
        char *ShowBuf = NULL;
        char string[9][15];
        water_temp = DS18B20_Get_Temp() / 10.0;

        uint32_t adc_value = 0;
    P1:
        if (bsp_dht11_read_TempAndHumidity(&DHT11_Data) == ERRCODE_SUCC) // 采集温湿度
        {

            bsp_ldr_get_value(ADC_CHANNEL_5, &adc_value); // 采集光照度，Lux
            ldr_value = 1500000 / (3300.0 - adc_value) / adc_value * 100.0;

            bsp_ldr_get_value(ADC_CHANNEL_2, &adc_value); // 采集PH值，PH
            PH = (7 - (adc_value / 1000.0 - 1.67) / 0.17748) + (25.0 - water_temp) * 0.003;

            bsp_ldr_get_value(ADC_CHANNEL_3, &adc_value); // 采集浑浊度，NTU
            if (adc_value > 1800)
                adc_value = 1800;
            turbidity = 2360.95 - (1311.64 * ((adc_value / 1000.0) + (0.0192 * (water_temp - 25.0))));

            bsp_ldr_get_value(ADC_CHANNEL_4, &adc_value); // 采集溶解度，ppm
            double turbidity_temp = adc_value / 1000.0 * (1 + 0.02 * (water_temp - 25.0));
            solubility = 66.71 * pow(turbidity_temp, 3) - 127.93 * pow(turbidity_temp, 2) + 428.7 * turbidity_temp;
            if (turbidity > 0)
            {
                sprintf(string[0], "%2d.%1d  ", DHT11_Data.temp_high8bit, DHT11_Data.temp_low8bit); // 环境温度
                sprintf(string[1], "%2d.%1d  ", DHT11_Data.humi_high8bit, DHT11_Data.humi_low8bit); // 环境湿度
                sprintf(string[2], "%.1f", ldr_value);                                              // 光照度
                sprintf(string[3], "%.1f", water_temp);                                             // 环境水温
                sprintf(string[4], "%.1f", PH);                                                     // PH值
                sprintf(string[5], "%.1f", solubility);                                             // 溶解度
                sprintf(string[6], "%.1f", turbidity);                                              // 浑浊度
                sprintf(string[7], "%.8lf", coordinate[0]);                                         // 经度
                sprintf(string[8], "%.8lf", coordinate[1]);                                         // 纬度

                for (uint8_t i = 0; i < 9; i++)
                {
                    osal_printk("%s,", string[i]);
                }
                osal_printk("\n");

                // 显示数据
                bsp_oled_DrawString(90, 24, string[1], Font_7x10, White);
                bsp_oled_DrawString(24, 44, string[2], Font_7x10, White);
                bsp_oled_DrawString(24, 24, string[0], Font_7x10, White);
                bsp_oled_UpdateScreen(); // 数据上报

                if (g_sle_status == 1)
                {

                    string[0][strlen(string[0]) - 2] = '\0';
                    string[1][strlen(string[1]) - 2] = '\0';
                    string[2][strlen(string[2]) - 2] = '\0';

                    ShowBuf = JSON_data_combination(string, 9);
                    if (ShowBuf != NULL)
                    {
                        // osal_printk(ShowBuf);
                        sle_server_send_report_by_handle((uint8_t *)ShowBuf, strlen(ShowBuf) + 1);
                        free(ShowBuf);
                    }
                }
            }
        }
        else
        {
            osal_printk("on\n");
            goto P1;
        }

        osal_msleep(1000);
    }
    return NULL;
}

static void ShipSystem_CollectionNode(void)
{
    osal_task *task_handle = NULL;

    osal_kthread_lock();

    task_handle = osal_kthread_create((osal_kthread_handler)ShipSystem_CollectionNode_task, 0, "ShipSystem_CollectionNode_Task", 0x1200);

    if (task_handle != NULL)
    {
        osal_kthread_set_priority(task_handle, 28);
    }

    osal_kthread_unlock();
}

/* Run the ShipSystem_CollectionNode. */
app_run(ShipSystem_CollectionNode);